package com.cyx.spring.utils;

import cn.hutool.core.util.StrUtil;
import com.cyx.spring.annotation.Bean;
import com.cyx.spring.annotation.Component;
import com.cyx.spring.expc.BeanDefinitionException;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * ClassUtils
 *
 * @author yongxiang
 * @date 2024/10/22 10:05
 * @desc
 */
public class ClassUtils {

    public static <A extends Annotation>  A findAnnotation(Class<?> clazz, Class<A> annotationClass){
        A annotation = clazz.getAnnotation(annotationClass);
        if (annotation != null){
            return annotation;
        }
        for (Annotation clazzAnnotation : clazz.getAnnotations()) {
            Class<? extends Annotation> annotationType = clazzAnnotation.annotationType();
            if (!annotationType.getPackage().getName().equals("java.lang.annotation")){
                A res = findAnnotation(annotationType, annotationClass);
                if (res != null){
                    return res;
                }
            }
        }
        return null;
    }

    /**
     * getBeanName by @Bean
     * @param method
     * @return
     */
    public static String getBeanName(Method method){
        Bean annotation = method.getAnnotation(Bean.class);
        String value = annotation.value();
        if (value.isEmpty()){
            value = method.getName();
        }
        return value;
    }

    /**
     * 获取beanName
     * @param clazz
     * @return
     */
    public static String getBeanName(Class<?> clazz){
        Component component = findAnnotation(clazz, Component.class);
        if (component != null){
            String value = component.value();
            if (!value.isEmpty()){
                return value;
            }
        }
        return StrUtil.lowerFirst(clazz.getSimpleName());
    }

    public static Method findAnnotationMethod(Class<?> clazz, Class<? extends Annotation> annotationClass){
        for (Method declaredMethod : clazz.getDeclaredMethods()) {
            Annotation annotation = declaredMethod.getAnnotation(annotationClass);
            if (annotation != null){
                return declaredMethod;
            }
        }
        return null;
    }

    /**
     * Get non-arg method by method name. Not search in super class.
     */
    public static Method getNamedMethod(Class<?> clazz, String methodName) {
        try {
            return clazz.getDeclaredMethod(methodName);
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException("Can't find method " + methodName + " in class " + clazz.getName(), e);
        }
    }

}
